package com.xinqi.common.mybatis.data.service.impl;

import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.utils.reflects.ReflectUtils;
import com.xinqi.common.mybatis.data.repo.SuperMapper;
import com.xinqi.common.mybatis.data.service.BaseService;
import com.xinqi.common.mybatis.injector.enums.ExtSqlMethod;
import org.apache.ibatis.binding.MapperMethod;
import org.apache.ibatis.session.SqlSession;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
 * mybatis 基础服务
 *
 * @author linkai
 * @since 2018/9/1
 */
public abstract class BaseServiceImpl<M extends SuperMapper<T>, T> extends ServiceImpl<M, T> implements BaseService<T> {

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(Collection<? extends Serializable> idx) {
        if (idx != null && !idx.isEmpty()) {
            return removeByIds(idx);
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteById(Serializable id) {
        if (Objects.nonNull(id)) {
            removeById(id);
            return true;
        }
        return false;
    }

    private T getDeleted(Serializable id) {
        T t = getById(id);
        if (t == null) {
            throw CommonErrors.BAD_REQUEST.asException("id有误，删除失败");
        }
        Class<?> aClass = t.getClass();
        try {
            t = (T) aClass.newInstance();
        } catch (Exception e) {
            return t;
        }
        Field deleted = ReflectUtils.getDeclaredFields(aClass, "deleted");
        /**
         * 没有deleted字段，则直接物理删除
         **/
        if (deleted == null) {
            removeById(id);
            return t;
        }
        Field idF = ReflectUtils.getDeclaredFields(aClass, "id");
        if (idF == null) {
            log.error(aClass.getName() + "id:" + id.toString() + "未取到");
            throw CommonErrors.BAD_REQUEST.asException("删除失败");
        } else {
            if (!ReflectUtils.setFiled(t, idF, id)) {
                throw CommonErrors.BAD_REQUEST.asException("删除失败");
            }
        }
        if (!ReflectUtils.setFiled(t, deleted, 1)) {
            throw CommonErrors.BAD_REQUEST.asException("删除失败");
        }
        Field deleteTime = ReflectUtils.getDeclaredFields(aClass, "deleteTime");
        if (deleteTime != null) {
            ReflectUtils.setFiled(t, deleteTime, System.currentTimeMillis());
        }
        return t;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean deletedByIds(List<Long> ids) {
        CommonErrors.BAD_REQUEST.check(ids != null, "IDS集合不能为空");
        if (CollectionUtils.isNotEmpty(ids)) {
            removeByIds(ids);

        }
        return true;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateAllColumnById(T entity) {
        return SqlHelper.retBool(baseMapper.updateAllColumnById(entity));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateBatchAllColumnById(Collection<T> entityList, int batchSize) {
        Assert.notEmpty(entityList, "error: entityList must not be empty");
        String sqlStatement = mapperClass.getName() + StringPool.DOT + ExtSqlMethod.UPDATE_ALL_COLUMN_BY_ID.getMethod();
        try (SqlSession batchSqlSession = SqlHelper.sqlSessionBatch(entityClass)) {
            int i = 0;
            for (T anEntityList : entityList) {
                MapperMethod.ParamMap<T> param = new MapperMethod.ParamMap<>();
                param.put(Constants.ENTITY, anEntityList);
                batchSqlSession.update(sqlStatement, param);
                if (i >= 1 && i % batchSize == 0) {
                    batchSqlSession.flushStatements();
                }
                i++;
            }
            batchSqlSession.flushStatements();
        }
        return true;
    }

    @Override
    public T selectByIdWithDeleted(Serializable id) {
        return baseMapper.selectByIdWithDeleted(id);
    }

}
